﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Threading;
using System.DirectoryServices;
using System.Collections;

using groupAnalyzer.Observers;
using groupAnalyzer.model;
using groupAnalyzer;
using groupAnalyzer.connectivity;

namespace groupAnalyzer.controller
{
    class Controller : ObserverClient
    {
        // maybe changed to queue for mass work
        private volatile Messages message;
        private volatile Thread myThread;
        private Factory factory;
        private object payLoad;

        private string lastObjectDN;
        private string lastAnalyzeMode;

        public void notify(Messages message, object payLoad)
        {
            this.message = message;
            this.payLoad = payLoad;
            // wake worker
            if (this.myThread.ThreadState == ThreadState.Suspended)
                this.myThread.Resume();
        }

        private void analyzeState(string objectDN, string analyzeMode)
        {
            // clear out all objects
            this.factory.reset();

            // saving parameters
            this.lastObjectDN = objectDN;
            this.lastAnalyzeMode = analyzeMode;

            LdapConnectivity connectivity = LdapConnectivity.constructLdapConnectivity();
            NodeAnalyzer analyzer = new NodeAnalyzer(this.factory, connectivity, objectDN, analyzeMode);
            analyzer.analyze();
            // now iterate over all groups and then read out the group members
            List<Node> groups = this.factory.getNodes();
            foreach (Node node in groups)
            {
                List<DirectoryEntry> usersOfGroupRaw = connectivity.getUsersOfGroup(node.FQDN);
                foreach (DirectoryEntry userRaw in usersOfGroupRaw)
                {
                    string username = connectivity.getProperty(userRaw, "name", 0);
                    string department = connectivity.getProperty(userRaw, "department", 0);
                    string email = connectivity.getProperty(userRaw, "mail", 0); ;
                    string fqdn = connectivity.getProperty(userRaw, "distinguishedName", 0); ;

                    User userOfGroup = this.factory.constructUser(username, department, email, fqdn);
                    node.addUser(userOfGroup);
                }
            }
            // finished work
            Observer.getGlobalObserver().notifiy(Messages.analyzed, null);
        }

        public void run()
        {
            while (true)
            {
                if (this.message == Messages.nothing)
                {
                    // be nice to cpu
                    this.myThread.Suspend();
                }
                switch (this.message)
                {
                    case Messages.refresh:
                        if (this.lastObjectDN == null)
                        {
                            // maybe change to do nothing...
                            Observer.getGlobalObserver().notifiy(Messages.error, "Nothing to refresh");
                            break;
                        }
                        this.analyzeState(this.lastObjectDN, this.lastAnalyzeMode);
                        break;

                    case Messages.analyze:
                        if (this.payLoad == null)
                        {
                            Observer.getGlobalObserver().notifiy(Messages.error, "No object dn given");
                            break;
                        }
                        List<object> payloadArray = ((List<object>)this.payLoad);
                        string objectDN = (string)payloadArray[0];
                        string analyzeModeString = (string)payloadArray[1];


                        if (!analyzeModeString.Equals("member"))
                        {
                            if (!analyzeModeString.Equals("memberof"))
                            {
                                Observer.getGlobalObserver().notifiy(Messages.error, "No valid analyzer mode given");
                                break;
                            }
                        }

                        this.analyzeState(objectDN, analyzeModeString);
                        break;

                    case Messages.exit:
                        Environment.Exit(0);
                        break;

                    default:
                        Console.WriteLine("unimplemented message " + message.ToString());
                        break;

                    case Messages.analyzed:
                    case Messages.nothing:
                        break;
                }
                // nothing to do any more - set it to nothing
                this.message = Messages.nothing;

            }
        }

        public Controller(Factory factory)
        {
            this.factory = factory;
            this.message = Messages.nothing;
            this.myThread = new Thread(new ThreadStart(this.run));
            myThread.Start();

        }

        public static void init(Factory factory)
        {
            Controller controller = new Controller(factory);
            Observer.getGlobalObserver().register(controller);

        }
    }
}
